package socket;

import android.os.Handler;
import android.os.Message;
import android.util.Log;

import container.ChatManager;

import com.jph.simple.LogonActivity;

import container.GroupManager;
import model.Msg;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import common.SystemUtil;
import container.FriendManager;
import container.PlayerContainer;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import utgame.UtMessage.MS_PlayerLogon;
import utgame.UtMessage.MS_PlayerChat;
import utgame.UtMessage.MS_GroupChat;
import utgame.UtMessage.MS_OfflineChat;
import utgame.UtMessage.MS_PlayerOnline;
import utgame.UtMessage.MS_PlayerOffline;
import utgame.UtMessage.MC_PlayerLogoff;
import utgame.UtMessage.MessagePacket;
import utgame.UtMessage.MessagePacket.MessageType;

import static common.Constant.UI_UPDATE_WEBSOCKET_OPEN;
import static common.Constant.URL_EXTRANET;
import static common.Constant.URL_INTRANET;

/**
 * Created by xueal on 2018/1/15.
 */

public class ServerSession {

    private static final ServerSession single = new ServerSession();

    public static ServerSession getInstance() {
        return single;
    }

    private HashMap<String, Handler> mHandlerMap = new HashMap<String, Handler>();

    public void addHandler(String name, Handler handler){
        mHandlerMap.put(name, handler);
    }
    public void removeHandler(String name){
        mHandlerMap.remove(name);
    }

    private Thread mWebSocketThread;

    final static OkHttpClient mOkHttpClient = new OkHttpClient.Builder()
            .readTimeout(3000, TimeUnit.SECONDS)//设置读取超时时间
            .writeTimeout(3000, TimeUnit.SECONDS)//设置写的超时时间
            .connectTimeout(3000, TimeUnit.SECONDS)//设置连接超时时间
            .build();

    WebSocket mWebSocketServer = null;

    private final ExecutorService sendExecutor = Executors.newSingleThreadExecutor();

    private WebSocketCall mWebSocketCall = null;


    public void startWebSocket(){

        mWebSocketThread = new Thread(){
            @Override
            public void run() {
                webSocketTest();
            }
        };
        mWebSocketThread.start();
    }
    public void stopWebSocket(){
        mWebSocketCall.cancel();
        mWebSocketThread.interrupt();
    }

    public void webSocketTest(){
//    boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
        String url = URL_EXTRANET;

        String deviceBrand = SystemUtil.getDeviceBrand();
        if (deviceBrand.toLowerCase().equals("android")
                || deviceBrand.toLowerCase().contains("86")
                || deviceBrand.toLowerCase().contains("64"))        // 模拟器的设备品牌为Android
        {
            url = URL_INTRANET;
        }
        final Request request = new Request.Builder().url(url).build();
        mWebSocketCall = WebSocketCall.create(mOkHttpClient, request);
        mWebSocketCall.enqueue(new WebSocketListener() {
            //            private final ExecutorService sendExecutor = Executors.newSingleThreadExecutor();
//            private WebSocket webSocket;
            @Override
            public void onOpen(WebSocket webSocket, Response response) {
                Log.d("WebSocketCall", "onOpen");

                mWebSocketServer = webSocket;

                Message msg = Message.obtain(mHandlerMap.get(LogonActivity.TAG), UI_UPDATE_WEBSOCKET_OPEN);
                msg.sendToTarget();
            }
            /**
             * 连接失败
             * @param e
             * @param response Present when the failure is a direct result of the response (e.g., failed
             * upgrade, non-101 response code, etc.). {@code null} otherwise.
             */
            @Override
            public void onFailure(IOException e, Response response) {
                Log.d("WebSocketCall","onFailure");
                mWebSocketServer = null;
            }

            /**
             * 接收到消息
             * @param message
             * @throws IOException
             */
            @Override
            public void onMessage(ResponseBody message) throws IOException {
//                final RequestBody response;
//                Log.d("WebSocketCall", "onMessage:" + message.source().readByteString().utf8());
                if (message.contentType() == WebSocket.TEXT) {//
//                    response = RequestBody.create(WebSocket.TEXT, "你好");//文本格式发送消息
                } else {
//                    BufferedSource source = message.source();
//                    Log.d("WebSocketCall", "onMessage:" + source.readByteString());
//                    response = RequestBody.create(WebSocket.BINARY, source.readByteString());
                    byte[] bytes = message.source().readByteArray();

                    MessagePacket messagePacket = MessagePacket.parseFrom(bytes);
                    MessagePacket.MessageType msgType = messagePacket.getType();
                    switch (msgType.getNumber()){
                        case MessageType.PlayerLogon_VALUE:
                            MS_PlayerLogon playerRegister = MS_PlayerLogon.parseFrom(messagePacket.getMsg());
                            PlayerContainer.getInstance().setNamePwd(playerRegister.getName(), playerRegister.getPwd());
                            break;
                        case MessageType.RequestFriends_VALUE:
                            FriendManager.getInstance().saveFriends(messagePacket.getMsg().toByteArray());
                            GroupManager.getInstance().saveGroups(messagePacket.getMsg().toByteArray());
                            break;
                        case MessageType.PlayerChat_VALUE:
                            MS_PlayerChat msPlayerChat = MS_PlayerChat.parseFrom(messagePacket.getMsg());
                            if (!msPlayerChat.getSenderName().equals(PlayerContainer.getInstance().getName())){
                                FriendManager.getInstance().getFriend(msPlayerChat.getSenderName()).addChat(new Msg(msPlayerChat.getChatContent(), Msg.TYPE_RECEIVED, msPlayerChat.getSenderName()));
                            }
                            break;
                        case MessageType.GroupChat_VALUE:
                            MS_GroupChat msGroupChat = MS_GroupChat.parseFrom(messagePacket.getMsg());
                            if (!msGroupChat.getSenderName().equals(PlayerContainer.getInstance().getName())) {
                                GroupManager.getInstance().getGroup(msGroupChat.getGroupName()).addChat(new Msg(msGroupChat.getChatContent(), Msg.TYPE_RECEIVED, msGroupChat.getSenderName()));
                            }
                            break;
                        case MessageType.PlayerOnline_VALUE:
                            MS_PlayerOnline msPlayerOnline = MS_PlayerOnline.parseFrom(messagePacket.getMsg());
                            FriendManager.getInstance().updateFriendOnline(msPlayerOnline.getName(), true);
                            break;
                        case MessageType.PlayerOffline_VALUE:
                            MS_PlayerOffline msPlayerOffline = MS_PlayerOffline.parseFrom(messagePacket.getMsg());
                            FriendManager.getInstance().updateFriendOnline(msPlayerOffline.getName(), false);
                            break;
                        case MessageType.OfflineChat_VALUE:
                            MS_OfflineChat msOfflineChat = MS_OfflineChat.parseFrom(messagePacket.getMsg().toByteArray());
                            ChatManager.getInstance().setOfflineChat(msOfflineChat);
                            break;
                        case MessageType.CreateGroup_VALUE:
                            GroupManager.getInstance().handleCreateGroup(messagePacket.getMsg().toByteArray());
                            break;

                    }

                    for (Map.Entry<String, Handler> entry : mHandlerMap.entrySet()) {
                        Message msg = Message.obtain(entry.getValue(), msgType.getNumber());
                        msg.obj = messagePacket.getMsg().toByteArray();
                        msg.sendToTarget();
                    }
                }
                message.source().close();       // 必须执行这行，否则崩溃
//                sendExecutor.execute(new Runnable() {
//                    @Override
//                    public void run() {
//                        try {
////                            Thread.sleep(1000*60);
//                            webSocket.sendMessage(response);//发送消息
//                        } catch (IOException e) {
//                            e.printStackTrace(System.out);
//                        } catch (Exception e) {
//                            e.printStackTrace();
//                        }
//                    }
//                });
            }

            @Override
            public void onPong(Buffer payload) {
                Log.d("WebSocketCall", "onPong:");
            }


            /**
             * 关闭
             * @param code The <a href="http://tools.ietf.org/html/rfc6455#section-7.4.1">RFC-compliant</a>
             * status code.
             * @param reason Reason for close or an empty string.
             */
            @Override
            public void onClose(int code, String reason) {
                sendExecutor.shutdown();
                mWebSocketServer = null;
            }
        });
    }

    public void sendMessage(MessagePacket.MessageType type, com.google.protobuf.ByteString msg) {
        MessagePacket.Builder builder = MessagePacket.newBuilder();
        builder.setType(type);
        builder.setMsg(msg);

        MessagePacket messagePacket = builder.build();
        byte[] buf = messagePacket.toByteArray();

        final RequestBody request = RequestBody.create(WebSocket.BINARY, buf);//文本格式发送消息
//        final RequestBody request = RequestBody.create(WebSocket.TEXT, "client...");//文本格式发送消息

        sendExecutor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    mWebSocketServer.sendMessage(request);//发送消息
                } catch (IOException e) {
                    e.printStackTrace(System.out);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public void playerLogOff(){
        MC_PlayerLogoff.Builder mcPlayerLogoffBuilder = MC_PlayerLogoff.newBuilder();
        mcPlayerLogoffBuilder.setName(PlayerContainer.getInstance().getName());

        sendMessage(MessageType.PlayerLogoff, mcPlayerLogoffBuilder.build().toByteString());
    }
}
